<!DOCTYPE html>
<html  lang="zh-CN" >
<head>
  <meta charset="UTF-8">
  <meta name="viewport"
    content="width=device-width, initial-scale=1.0, minimum-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <meta name="theme-color" content="#fff" id="theme-color">
  <meta name="description" content="深山磨柴斧，一鸣震江湖">
  <link rel="icon" href="/img/ic_head.jpg">
  <title>018-Android自定义View(13)：自定义手势存储及使用详解(图文)</title>
  
  
  <meta property="og:title" content="018-Android自定义View(13)：自定义手势存储及使用详解(图文)">
  
  
  <meta property="og:url" content="http://example.com/2019/08/08/018-Android%E8%87%AA%E5%AE%9A%E4%B9%89View(13)%EF%BC%9A%E8%87%AA%E5%AE%9A%E4%B9%89%E6%89%8B%E5%8A%BF%E5%AD%98%E5%82%A8%E5%8F%8A%E4%BD%BF%E7%94%A8%E8%AF%A6%E8%A7%A3(%E5%9B%BE%E6%96%87)/index.html">
  
  
  <meta property="og:img" content="/img/ic_head.jpg">
  
  
  <meta property="og:img" content="深山磨柴斧，一鸣震江湖">
  
  
  <meta property="og:type" content="article">
  <meta property="og:article:published_time" content="2019-08-08">
  <meta property="og:article:modified_time" content="2021-04-14">
  <meta property="og:article:author" content="Cupster">
  
  
  <meta property="og:article:tag" content="Android">
  
  <meta property="og:article:tag" content="Android自定义View">
  
  <meta property="og:article:tag" content="Android事件">
  
  <meta property="og:article:tag" content="Android手势">
  
  
  
  
  <script>
    // control reverse button
    var reverseDarkList = {
      dark: 'light',
      light: 'dark'
    };
    var themeColor = {
      dark: '#1c1c1e',
      light: '#fff'
    }
    // get the data of css prefers-color-scheme
    var getCssMediaQuery = function() {
      return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
    };
    // reverse current darkmode setting function
    var reverseDarkModeSetting = function() {
      var setting = localStorage.getItem('user-color-scheme');
      if(reverseDarkList[setting]) {
        setting = reverseDarkList[setting];
      } else if(setting === null) {
        setting = reverseDarkList[getCssMediaQuery()];
      } else {
        return;
      }
      localStorage.setItem('user-color-scheme', setting);
      return setting;
    };
    // apply current darkmode setting
    var setDarkmode = function(mode) {
      var setting = mode || localStorage.getItem('user-color-scheme');
      if(setting === getCssMediaQuery()) {
        document.documentElement.removeAttribute('data-user-color-scheme');
        localStorage.removeItem('user-color-scheme');
        document.getElementById('theme-color').content = themeColor[setting];
      } else if(reverseDarkList[setting]) {
        document.documentElement.setAttribute('data-user-color-scheme', setting);
        document.getElementById('theme-color').content = themeColor[setting];
      } else {
        document.documentElement.removeAttribute('data-user-color-scheme');
        localStorage.removeItem('user-color-scheme');
        document.getElementById('theme-color').content = themeColor[getCssMediaQuery()];
      }
    };
    setDarkmode();
  </script>
  <script>
    function loadScript(url, cb) {
      var script = document.createElement('script');
      script.src = url;
      if (cb) script.onload = cb;
      script.async = true;
      document.body.appendChild(script);
    }
  </script>
  
  <link rel="preload" href="//at.alicdn.com/t/font_1946621_i1kgafibvw.css" as="style" >
  <link rel="preload" href="//at.alicdn.com/t/font_1952792_89b4ac4k4up.css" as="style" >
  
  <link rel="preload" href="/js/lib/lightbox/baguetteBox.min.js" as="script">
  <link rel="preload" href="/js/lib/lightbox/baguetteBox.min.css" as="style" >
  
  
  <link rel="preload" href="/js/lib/lozad.min.js" as="script">
  
  
  
  
  
  
  
  
<link rel="stylesheet" href="/css/main.css">

  
  
<link rel="stylesheet" href="//at.alicdn.com/t/font_1946621_i1kgafibvw.css">

  
  
<link rel="stylesheet" href="//at.alicdn.com/t/font_1952792_89b4ac4k4up.css">

  
  
<link rel="stylesheet" href="/js/lib/lightbox/baguetteBox.min.css">

  
  
  
  
<meta name="generator" content="Hexo 5.4.0"></head>


<body>
  <div class="wrapper">
    
    <nav class="navbar">
  <div class="navbar-logo">
    <span class="navbar-logo-main">
      
      <img class="navbar-logo-img" src="/img/ic_head.jpg" alt="logo">
      
      <span class="navbar-logo-dsc">不负明天</span>
    </span>
  </div>
  <div class="navbar-menu">
    
    <a href="/" class="navbar-menu-item">
    
    首页
    
    </a>
    
    <a href="/archives" class="navbar-menu-item">
    
    归档
    
    </a>
    
    <a href="/tags" class="navbar-menu-item">
    
    标签
    
    </a>
    
    <a href="/categories" class="navbar-menu-item">
    
    分类
    
    </a>
    
    <a href="/about" class="navbar-menu-item">
    
    关于
    
    </a>
    
    <a href="/links" class="navbar-menu-item">
    
    友链
    
    </a>
    
    <a class="navbar-menu-item darknavbar" id="dark"><i class="iconfont icon-weather"></i></a>
    <a class="navbar-menu-item searchnavbar" id="search"><i class="iconfont icon-search" style="font-size: 1.2rem; font-weight: 400;"></i></a>
  </div>
</nav>
    
    <div id="local-search" style="display: none;">
      <input class="navbar-menu-item" id="search-input" placeholder="请输入搜索内容...">
      <div id="search-content"></div>
    </div>
    
    <div class="section-wrap">
      <div class="container">
        <div class="columns">
          <main class="main-column">
<article class="card card-content">
  <header>
    <h1 class="post-title">
      018-Android自定义View(13)：自定义手势存储及使用详解(图文)
    </h1>
  </header>
  <div class="post-meta post-show-meta">
    <time datetime="2019-08-08T04:11:37.000Z">
      <i class="iconfont icon-calendar" style="margin-right: 2px;"></i>
      <span>2019-08-08</span>
    </time>
    
    <span class="dot"></span>
    
    <a href="/categories/Android/" class="post-meta-link">Android</a>
    
    
    
    <span class="dot"></span>
    <span>4.3k 字</span>
    
  </div>
  
  <div class="post-meta post-show-meta" style="margin-top: -10px;">
    <div style="display: flex; align-items: center;">
      <i class="iconfont icon-biaoqian" style="margin-right: 2px; font-size: 1.15rem;"></i>
      
      
        <a href="/tags/Android/" class="post-meta-link">Android</a>
      
      
      <span class="dot"></span>
      
        <a href="/tags/Android自定义View/" class="post-meta-link">Android自定义View</a>
      
      
      <span class="dot"></span>
      
        <a href="/tags/Android事件/" class="post-meta-link">Android事件</a>
      
      
      <span class="dot"></span>
      
        <a href="/tags/Android手势/" class="post-meta-link">Android手势</a>
      
    </div>
  </div>
  
  </header>
  <div id="section" class="post-content">
    <p><a target="_blank" rel="noopener" href="https://blog.csdn.net/Cupster/article/details/113262592">【5年Android从零复盘系列之十八】Android自定义View(13)：自定义手势存储及使用</a></p>
<hr />

<h1 id="1-基础"><a href="#1-基础" class="headerlink" title="1.基础"></a>1.基础</h1><ol>
<li>掌握View体系事件分发与处理，参考<a target="_blank" rel="noopener" href="https://blog.csdn.net/Cupster/article/details/112900623">Android自定义View(9)：事件分发&amp;处理</a></li>
<li>掌握基础的手势监听及手势动作有关的回调时机，参考<a target="_blank" rel="noopener" href="https://blog.csdn.net/Cupster/article/details/112988157">Android自定义View(10)：手势监听&amp;处理</a></li>
<li>了解GestureLibrary和GestureOverlayView的api使用，参考<a target="_blank" rel="noopener" href="http://www.android-doc.com/reference/android/gesture/package-summary.html">官方API文档</a></li>
<li>了解自定义手势绘制及其原理</li>
</ol>
<h1 id="2-存储手势"><a href="#2-存储手势" class="headerlink" title="2.存储手势"></a>2.存储手势</h1><p>手势绘制请参考<a target="_blank" rel="noopener" href="https://blog.csdn.net/Cupster/article/details/113261905">Android自定义View(12)：手势绘制及GestureOverlayView事件浅析</a></p>
<pre><code>1.如绘制手势的代码，添加声明GestureLibrary对象，并初始化
2.添加动态请求使用存储权限
3.设置手势文件存储路径
</code></pre>
<img src="https://gitee.com/cupster/picbed/raw/master/uPic/20210127175953_绘制G.gif" / srcset="data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%20300%20300'%3E%3C/svg%3E" data-src="https://gitee.com/cupster/picbed/raw/master/uPic/20210127175953_绘制G.gif" class="lozad post-image">

<h2 id="2-1代码及注释"><a href="#2-1代码及注释" class="headerlink" title="2.1代码及注释"></a>2.1代码及注释</h2><pre class="highlight"><span class="line"><span class="keyword">package</span> com.cupster.android_x_frame;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> android.content.Context;</span><br><span class="line"><span class="keyword">import</span> android.content.pm.PackageManager;</span><br><span class="line"><span class="keyword">import</span> android.gesture.Gesture;</span><br><span class="line"><span class="keyword">import</span> android.gesture.GestureLibraries;</span><br><span class="line"><span class="keyword">import</span> android.gesture.GestureLibrary;</span><br><span class="line"><span class="keyword">import</span> android.gesture.GestureOverlayView;</span><br><span class="line"><span class="keyword">import</span> android.graphics.Bitmap;</span><br><span class="line"><span class="keyword">import</span> android.graphics.Color;</span><br><span class="line"><span class="keyword">import</span> android.os.Bundle;</span><br><span class="line"><span class="keyword">import</span> android.os.Environment;</span><br><span class="line"><span class="keyword">import</span> android.text.TextUtils;</span><br><span class="line"><span class="keyword">import</span> android.view.View;</span><br><span class="line"><span class="keyword">import</span> android.widget.TextView;</span><br><span class="line"><span class="keyword">import</span> android.widget.Toast;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.io.File;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> androidx.annotation.NonNull;</span><br><span class="line"><span class="keyword">import</span> androidx.appcompat.app.AppCompatActivity;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">DrawGestureActivity</span> <span class="keyword">extends</span> <span class="title">AppCompatActivity</span> <span class="keyword">implements</span> <span class="title">GestureOverlayView</span>.<span class="title">OnGesturePerformedListener</span>, <span class="title">GestureOverlayView</span>.<span class="title">OnGesturingListener</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    GestureOverlayView mGestureOverlayView;</span><br><span class="line">    TextView mTvHint;</span><br><span class="line">    ConfirmDialog mDialog;</span><br><span class="line"></span><br><span class="line">    GestureLibrary mGestureLibrary;</span><br><span class="line">    File mFileGesture = <span class="keyword">null</span>;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">protected</span> <span class="keyword">void</span> <span class="title">onCreate</span><span class="params">(Bundle savedInstanceState)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">super</span>.onCreate(savedInstanceState);</span><br><span class="line">        setContentView(R.layout.activity_draw_gesture);</span><br><span class="line">        mGestureOverlayView = findViewById(R.id.gesture_overlay);</span><br><span class="line">        mTvHint = findViewById(R.id.text);</span><br><span class="line"></span><br><span class="line">        mGestureOverlayView.setFadeOffset(<span class="number">800</span>);<span class="comment">//默认420ms,设置为1600ms</span></span><br><span class="line">        mGestureOverlayView.setGestureStrokeType(GestureOverlayView.GESTURE_STROKE_TYPE_MULTIPLE);<span class="comment">//默认单指连续绘制，设置为多指绘制</span></span><br><span class="line">        mGestureOverlayView.setGestureStrokeWidth(<span class="number">10</span>);<span class="comment">//绘制线宽</span></span><br><span class="line">        mGestureOverlayView.setGestureColor(Color.parseColor(<span class="string">&quot;#3ca1f9&quot;</span>));<span class="comment">//绘制颜色</span></span><br><span class="line">        mGestureOverlayView.setUncertainGestureColor(Color.parseColor(<span class="string">&quot;#a7dbf7&quot;</span>));<span class="comment">//渐成色</span></span><br><span class="line">        <span class="comment">//设置监听</span></span><br><span class="line">        mGestureOverlayView.addOnGesturePerformedListener(<span class="keyword">this</span>);</span><br><span class="line">        mGestureOverlayView.addOnGesturingListener(<span class="keyword">this</span>);</span><br><span class="line">        <span class="comment">//设置手势-存储位置</span></span><br><span class="line">        PermissionUtil.applyPermission(<span class="keyword">this</span> ,<span class="number">101</span> ,BuildConfig.APPLICATION_ID);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">protected</span> <span class="keyword">void</span> <span class="title">onDestroy</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        mGestureOverlayView.removeOnGesturePerformedListener(<span class="keyword">this</span>);</span><br><span class="line">        mGestureOverlayView.removeOnGesturingListener(<span class="keyword">this</span>);</span><br><span class="line">        <span class="keyword">super</span>.onDestroy();</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">onRequestPermissionsResult</span><span class="params">(<span class="keyword">int</span> requestCode, <span class="meta">@NonNull</span> String[] permissions, <span class="meta">@NonNull</span> <span class="keyword">int</span>[] grantResults)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">switch</span> (requestCode) &#123;</span><br><span class="line">            <span class="keyword">case</span> <span class="number">101</span>:</span><br><span class="line">                <span class="keyword">if</span> (grantResults.length &gt; <span class="number">0</span> &amp;&amp; grantResults[<span class="number">0</span>] == PackageManager.PERMISSION_GRANTED) &#123;</span><br><span class="line">                    initStoreFile();<span class="comment">//外部存储方式</span></span><br><span class="line">                &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">                    Toast.makeText(<span class="keyword">this</span>, <span class="string">&quot;权限限制，可能无法正常使用主要功能&quot;</span>, Toast.LENGTH_SHORT).show();</span><br><span class="line">                    PermissionUtil.skipPermissionSetting(<span class="keyword">this</span>);</span><br><span class="line">                &#125;</span><br><span class="line">                <span class="keyword">break</span>;</span><br><span class="line">            <span class="keyword">default</span>:</span><br><span class="line">                <span class="keyword">break</span>;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">initStoreFile</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">if</span> (mFileGesture == <span class="keyword">null</span> &amp;&amp; Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) &#123;</span><br><span class="line">            mFileGesture = <span class="keyword">new</span> File(Environment.getExternalStorageDirectory(), <span class="string">&quot;gesture&quot;</span>);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">if</span> (mGestureLibrary == <span class="keyword">null</span>) &#123;</span><br><span class="line">            mGestureLibrary = GestureLibraries.fromFile(mFileGesture);<span class="comment">//方式1</span></span><br><span class="line"><span class="comment">//            mGestureLibrary = GestureLibraries.fromPrivateFile(this ,Environment.getExternalStorageDirectory()+&quot;gesture&quot;);//方式2</span></span><br><span class="line"><span class="comment">//            mGestureLibrary = GestureLibraries.fromRawResource(this ,R.raw.gesture);//方式3</span></span><br><span class="line">            mGestureLibrary.load();</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">int</span> <span class="title">dp2px</span><span class="params">(Context context, <span class="keyword">float</span> dpValue)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">final</span> <span class="keyword">float</span> scale = context.getResources().getDisplayMetrics().density;</span><br><span class="line">        <span class="keyword">return</span> (<span class="keyword">int</span>) (dpValue * scale + <span class="number">0.5f</span>);</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="comment">//==============================================</span></span><br><span class="line">    <span class="comment">//=========GesturePerformedListener=============</span></span><br><span class="line">    <span class="comment">//==============================================</span></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">onGesturePerformed</span><span class="params">(GestureOverlayView gestureOverlayView, Gesture gesture)</span> </span>&#123;</span><br><span class="line">        mTvHint.append(<span class="string">&quot;\n&quot;</span>);</span><br><span class="line">        mTvHint.append(<span class="string">&quot;--&gt; 所有绘制路径，识别完成&quot;</span>);</span><br><span class="line">        confirmGesture(gesture);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">confirmGesture</span><span class="params">(<span class="keyword">final</span> Gesture gesture)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">if</span> (mDialog != <span class="keyword">null</span> &amp;&amp; mDialog.isVisible()) &#123;</span><br><span class="line">            mDialog.dismiss();</span><br><span class="line">            mDialog = <span class="keyword">null</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        Bitmap bitmap = gesture.toBitmap(dp2px(<span class="keyword">this</span>, <span class="number">100</span>), dp2px(<span class="keyword">this</span>, <span class="number">100</span>), <span class="number">10</span>, Color.parseColor(<span class="string">&quot;#3ca1f9&quot;</span>));</span><br><span class="line">        mDialog = ConfirmDialog.build(<span class="string">&quot;gesture&quot;</span>, bitmap);</span><br><span class="line">        mDialog.setConfirmListener(<span class="keyword">new</span> View.OnClickListener() &#123;</span><br><span class="line">            <span class="meta">@Override</span></span><br><span class="line">            <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">onClick</span><span class="params">(View view)</span> </span>&#123;</span><br><span class="line">                String name = String.valueOf(view.getTag());</span><br><span class="line">                <span class="keyword">if</span> (TextUtils.isEmpty(name)) &#123;</span><br><span class="line">                    Toast.makeText(DrawGestureActivity.<span class="keyword">this</span>, <span class="string">&quot;请输入手势名称&quot;</span>, Toast.LENGTH_SHORT).show();</span><br><span class="line">                    <span class="keyword">return</span>;</span><br><span class="line">                &#125;</span><br><span class="line"></span><br><span class="line">                initStoreFile();<span class="comment">//校验，防止内存对象丢失-&gt;null</span></span><br><span class="line"></span><br><span class="line">                mGestureLibrary.addGesture(name, gesture);</span><br><span class="line">                mGestureLibrary.save();</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;);</span><br><span class="line">        mDialog.show(getSupportFragmentManager(), <span class="string">&quot;gesture_dialog&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">//===============================================</span></span><br><span class="line">    <span class="comment">//=========GesturingListener=====================</span></span><br><span class="line">    <span class="comment">//===============================================</span></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">onGesturingStarted</span><span class="params">(GestureOverlayView gestureOverlayView)</span> </span>&#123;</span><br><span class="line">        mTvHint.append(<span class="string">&quot;\n&quot;</span>);</span><br><span class="line">        mTvHint.append(<span class="string">&quot;--&gt; 单笔手势绘制开始&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">onGesturingEnded</span><span class="params">(GestureOverlayView gestureOverlayView)</span> </span>&#123;</span><br><span class="line">        mTvHint.append(<span class="string">&quot;\n&quot;</span>);</span><br><span class="line">        mTvHint.append(<span class="string">&quot;--&gt; 单笔手势绘制结束&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre>

<p>activity_draw_gesture.xml</p>
<pre class="highlight"><span class="line"><span class="meta">&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">RelativeLayout</span> <span class="attr">xmlns:android</span>=<span class="string">&quot;http://schemas.android.com/apk/res/android&quot;</span></span></span><br><span class="line"><span class="tag">    <span class="attr">xmlns:app</span>=<span class="string">&quot;http://schemas.android.com/apk/res-auto&quot;</span></span></span><br><span class="line"><span class="tag">    <span class="attr">xmlns:tools</span>=<span class="string">&quot;http://schemas.android.com/tools&quot;</span></span></span><br><span class="line"><span class="tag">    <span class="attr">android:layout_width</span>=<span class="string">&quot;match_parent&quot;</span></span></span><br><span class="line"><span class="tag">    <span class="attr">android:layout_height</span>=<span class="string">&quot;match_parent&quot;</span></span></span><br><span class="line"><span class="tag">    <span class="attr">tools:context</span>=<span class="string">&quot;.MainActivity&quot;</span>&gt;</span></span><br><span class="line">    &lt;android.gesture.GestureOverlayView</span><br><span class="line">        android:id=&quot;@+id/gesture_overlay&quot;</span><br><span class="line">        android:layout_width=&quot;match_parent&quot;</span><br><span class="line">        android:layout_height=&quot;match_parent&quot;</span><br><span class="line">        &gt;</span><br><span class="line">        &lt;LinearLayout</span><br><span class="line">            android:layout_width=&quot;match_parent&quot;</span><br><span class="line">            android:orientation=&quot;vertical&quot;</span><br><span class="line">            android:gravity=&quot;center&quot;</span><br><span class="line">            android:layout_height=&quot;match_parent&quot;&gt;</span><br><span class="line">            &lt;TextView</span><br><span class="line">                android:id=&quot;@+id/text&quot;</span><br><span class="line">                android:text=&quot;测试显示&quot;</span><br><span class="line">                android:layout_width=&quot;wrap_content&quot;</span><br><span class="line">                android:layout_height=&quot;wrap_content&quot;/&gt;</span><br><span class="line">        <span class="tag">&lt;/<span class="name">LinearLayout</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">android.gesture.GestureOverlayView</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">RelativeLayout</span>&gt;</span></span><br></pre>

<p><strong>对话框等次要代码见文末附。</strong></p>
<h1 id="3-读取-使用手势"><a href="#3-读取-使用手势" class="headerlink" title="3.读取/使用手势"></a>3.读取/使用手势</h1><pre><code>1.思路基本与绘制过程一致
2.在绘制完成回调onGesturePerformed中，进行手势对比
</code></pre>
<img src="https://gitee.com/cupster/picbed/raw/master/uPic/20210127180216_识别G.gif" / srcset="data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%20300%20300'%3E%3C/svg%3E" data-src="https://gitee.com/cupster/picbed/raw/master/uPic/20210127180216_识别G.gif" class="lozad post-image">


<img src="https://gitee.com/cupster/picbed/raw/master/uPic/20210127180616_IRMxHc.png" / srcset="data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%20300%20300'%3E%3C/svg%3E" data-src="https://gitee.com/cupster/picbed/raw/master/uPic/20210127180616_IRMxHc.png" class="lozad post-image">



<pre class="highlight"><span class="line"><span class="keyword">package</span> com.cupster.android_x_frame;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> android.content.pm.PackageManager;</span><br><span class="line"><span class="keyword">import</span> android.gesture.Gesture;</span><br><span class="line"><span class="keyword">import</span> android.gesture.GestureLibraries;</span><br><span class="line"><span class="keyword">import</span> android.gesture.GestureLibrary;</span><br><span class="line"><span class="keyword">import</span> android.gesture.GestureOverlayView;</span><br><span class="line"><span class="keyword">import</span> android.gesture.Prediction;</span><br><span class="line"><span class="keyword">import</span> android.graphics.Color;</span><br><span class="line"><span class="keyword">import</span> android.os.Bundle;</span><br><span class="line"><span class="keyword">import</span> android.os.Environment;</span><br><span class="line"><span class="keyword">import</span> android.widget.TextView;</span><br><span class="line"><span class="keyword">import</span> android.widget.Toast;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.io.File;</span><br><span class="line"><span class="keyword">import</span> java.util.ArrayList;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> androidx.annotation.NonNull;</span><br><span class="line"><span class="keyword">import</span> androidx.annotation.Nullable;</span><br><span class="line"><span class="keyword">import</span> androidx.appcompat.app.AppCompatActivity;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">DetectionActivity</span> <span class="keyword">extends</span> <span class="title">AppCompatActivity</span> <span class="keyword">implements</span> <span class="title">GestureOverlayView</span>.<span class="title">OnGesturePerformedListener</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    GestureOverlayView mGestureOverlayView;</span><br><span class="line">    TextView mTvHint;</span><br><span class="line"></span><br><span class="line">    GestureLibrary mGestureLibrary;</span><br><span class="line">    File mFileGesture = <span class="keyword">null</span>;</span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">protected</span> <span class="keyword">void</span> <span class="title">onCreate</span><span class="params">(<span class="meta">@Nullable</span> Bundle savedInstanceState)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">super</span>.onCreate(savedInstanceState);</span><br><span class="line"></span><br><span class="line">        setContentView(R.layout.activity_draw_gesture);</span><br><span class="line">        mGestureOverlayView = findViewById(R.id.gesture_overlay);</span><br><span class="line">        mTvHint = findViewById(R.id.text);</span><br><span class="line"></span><br><span class="line">        mGestureOverlayView.setFadeOffset(<span class="number">800</span>);<span class="comment">//默认420ms,设置为1600ms</span></span><br><span class="line">        mGestureOverlayView.setGestureStrokeType(GestureOverlayView.GESTURE_STROKE_TYPE_MULTIPLE);<span class="comment">//默认单指连续绘制，设置为多指绘制</span></span><br><span class="line">        mGestureOverlayView.setGestureStrokeWidth(<span class="number">10</span>);<span class="comment">//绘制线宽</span></span><br><span class="line">        mGestureOverlayView.setGestureColor(Color.parseColor(<span class="string">&quot;#3ca1f9&quot;</span>));<span class="comment">//绘制颜色</span></span><br><span class="line">        mGestureOverlayView.setUncertainGestureColor(Color.parseColor(<span class="string">&quot;#a7dbf7&quot;</span>));<span class="comment">//渐成色</span></span><br><span class="line">        <span class="comment">//设置监听</span></span><br><span class="line">        mGestureOverlayView.addOnGesturePerformedListener(<span class="keyword">this</span>);</span><br><span class="line">        <span class="comment">//1.文件方式</span></span><br><span class="line">        PermissionUtil.applyPermission(<span class="keyword">this</span> ,<span class="number">101</span> ,BuildConfig.APPLICATION_ID);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">protected</span> <span class="keyword">void</span> <span class="title">onDestroy</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        mGestureOverlayView.removeOnGesturePerformedListener(<span class="keyword">this</span>);</span><br><span class="line">        <span class="keyword">super</span>.onDestroy();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">onRequestPermissionsResult</span><span class="params">(<span class="keyword">int</span> requestCode, <span class="meta">@NonNull</span> String[] permissions, <span class="meta">@NonNull</span> <span class="keyword">int</span>[] grantResults)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">switch</span> (requestCode)&#123;</span><br><span class="line">            <span class="keyword">case</span> <span class="number">101</span>:</span><br><span class="line">                <span class="keyword">if</span> (grantResults.length &gt;<span class="number">0</span> &amp;&amp; grantResults[<span class="number">0</span>] == PackageManager.PERMISSION_GRANTED)&#123;</span><br><span class="line">                    initStoreFile();<span class="comment">//外部存储方式</span></span><br><span class="line">                &#125;<span class="keyword">else</span> &#123;</span><br><span class="line">                    Toast.makeText(<span class="keyword">this</span>, <span class="string">&quot;权限限制，可能无法正常使用主要功能&quot;</span>, Toast.LENGTH_SHORT).show();</span><br><span class="line">                    PermissionUtil.skipPermissionSetting(<span class="keyword">this</span>);</span><br><span class="line">                &#125;</span><br><span class="line">                <span class="keyword">break</span>;</span><br><span class="line">            <span class="keyword">default</span>:</span><br><span class="line">                <span class="keyword">break</span>;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">initStoreFile</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">if</span> (mFileGesture == <span class="keyword">null</span> &amp;&amp; Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) &#123;</span><br><span class="line">            mFileGesture = <span class="keyword">new</span> File(Environment.getExternalStorageDirectory(), <span class="string">&quot;gesture&quot;</span>);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">if</span> (mGestureLibrary == <span class="keyword">null</span> )&#123;</span><br><span class="line">            mGestureLibrary = GestureLibraries.fromFile(mFileGesture);<span class="comment">//方式1</span></span><br><span class="line"><span class="comment">//            mGestureLibrary = GestureLibraries.fromPrivateFile(this ,Environment.getExternalStorageDirectory()+&quot;gesture&quot;);//方式2</span></span><br><span class="line"><span class="comment">//            mGestureLibrary = GestureLibraries.fromRawResource(this ,R.raw.gesture);//方式3</span></span><br><span class="line">            <span class="keyword">boolean</span> flag = mGestureLibrary.load();</span><br><span class="line">            mTvHint.append(<span class="string">&quot;\n&quot;</span>);</span><br><span class="line">            mTvHint.append(<span class="string">&quot;load  = &quot;</span>+flag);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">onGesturePerformed</span><span class="params">(GestureOverlayView gestureOverlayView, Gesture gesture)</span> </span>&#123;</span><br><span class="line">        mTvHint.append(<span class="string">&quot;\n&quot;</span>);</span><br><span class="line">        mTvHint.append(<span class="string">&quot;--&gt; 所有绘制路径，识别完成&quot;</span>);</span><br><span class="line"></span><br><span class="line">        initStoreFile();<span class="comment">//校验</span></span><br><span class="line"></span><br><span class="line">        mGestureLibrary.setOrientationStyle(<span class="number">4</span>);</span><br><span class="line"></span><br><span class="line">        ArrayList&lt;Prediction&gt; predictions = mGestureLibrary.recognize(gesture);</span><br><span class="line">        mTvHint.append(<span class="string">&quot;\n&quot;</span>);</span><br><span class="line">        mTvHint.append(<span class="string">&quot;识别数量：--&gt; &quot;</span>+predictions.size());</span><br><span class="line">        <span class="keyword">for</span> (Prediction p : predictions)&#123;</span><br><span class="line">            mTvHint.append(<span class="string">&quot;\n&quot;</span>);</span><br><span class="line">            mTvHint.append(p.name+<span class="string">&quot;匹配值--&gt; &quot;</span>+p.score);</span><br><span class="line">            <span class="keyword">if</span> (p.score &gt;<span class="number">3.0</span>)&#123;<span class="comment">//匹配阈值值越大，要求匹配精度更高</span></span><br><span class="line">                mTvHint.append(<span class="string">&quot;\n&quot;</span>);</span><br><span class="line">                mTvHint.append(<span class="string">&quot;匹配到--&gt; &quot;</span>+p.name);</span><br><span class="line"></span><br><span class="line">                doSomeThing();<span class="comment">//触发事件</span></span><br><span class="line"><span class="comment">//                break;//实际使用时，放开注释，此处为测试显示其他不匹配手势 &amp; 识别结果</span></span><br><span class="line">            &#125;<span class="keyword">else</span> &#123;</span><br><span class="line">                mTvHint.append(<span class="string">&quot;\n&quot;</span>);</span><br><span class="line">                mTvHint.append(p.name+<span class="string">&quot;--&gt; 不匹配&quot;</span>);</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">doSomeThing</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        mTvHint.append(<span class="string">&quot;\n&quot;</span>);</span><br><span class="line">        mTvHint.append(<span class="string">&quot;===================\n&quot;</span>);</span><br><span class="line">        mTvHint.append(<span class="string">&quot;触发--&gt;调用事件&quot;</span>);</span><br><span class="line">        mTvHint.append(<span class="string">&quot;\n&quot;</span>);</span><br><span class="line">        mTvHint.append(<span class="string">&quot;===================&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre>


<h1 id="4-附-相关次要代码"><a href="#4-附-相关次要代码" class="headerlink" title="4.附 相关次要代码"></a>4.附 相关次要代码</h1><h2 id="4-1-ConfirmDialog-java"><a href="#4-1-ConfirmDialog-java" class="headerlink" title="4.1 ConfirmDialog.java"></a>4.1 ConfirmDialog.java</h2><pre class="highlight"><span class="line"><span class="keyword">package</span> com.cupster.android_x_frame;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> android.content.Context;</span><br><span class="line"><span class="keyword">import</span> android.graphics.Bitmap;</span><br><span class="line"><span class="keyword">import</span> android.graphics.Color;</span><br><span class="line"><span class="keyword">import</span> android.graphics.drawable.ColorDrawable;</span><br><span class="line"><span class="keyword">import</span> android.os.Bundle;</span><br><span class="line"><span class="keyword">import</span> android.text.TextUtils;</span><br><span class="line"><span class="keyword">import</span> android.util.Log;</span><br><span class="line"><span class="keyword">import</span> android.view.Gravity;</span><br><span class="line"><span class="keyword">import</span> android.view.LayoutInflater;</span><br><span class="line"><span class="keyword">import</span> android.view.View;</span><br><span class="line"><span class="keyword">import</span> android.view.ViewGroup;</span><br><span class="line"><span class="keyword">import</span> android.view.Window;</span><br><span class="line"><span class="keyword">import</span> android.view.WindowManager;</span><br><span class="line"><span class="keyword">import</span> android.widget.Button;</span><br><span class="line"><span class="keyword">import</span> android.widget.EditText;</span><br><span class="line"><span class="keyword">import</span> android.widget.ImageView;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> androidx.annotation.NonNull;</span><br><span class="line"><span class="keyword">import</span> androidx.annotation.Nullable;</span><br><span class="line"><span class="keyword">import</span> androidx.fragment.app.DialogFragment;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">ConfirmDialog</span> <span class="keyword">extends</span> <span class="title">DialogFragment</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">final</span> String KEY_NAME =<span class="string">&quot;NAME&quot;</span>;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">final</span> String KEY_IMG =<span class="string">&quot;NAME&quot;</span>;</span><br><span class="line"></span><br><span class="line">    View mView;</span><br><span class="line">    ImageView mImg;</span><br><span class="line">    EditText mInput;</span><br><span class="line">    Button mBtn;</span><br><span class="line"></span><br><span class="line">    View.OnClickListener mConfirmListener;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span>  <span class="keyword">static</span>  ConfirmDialog <span class="title">build</span><span class="params">( String name ,Bitmap bitmap)</span></span>&#123;</span><br><span class="line">        ConfirmDialog dialog = <span class="keyword">new</span> ConfirmDialog();</span><br><span class="line">        Bundle bundle = <span class="keyword">new</span> Bundle();</span><br><span class="line">        bundle.putString(KEY_NAME ,name);</span><br><span class="line">        bundle.putParcelable(KEY_IMG ,bitmap);</span><br><span class="line">        dialog.setArguments(bundle);</span><br><span class="line">        <span class="keyword">return</span> dialog;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Nullable</span></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> View <span class="title">onCreateView</span><span class="params">(<span class="meta">@NonNull</span> LayoutInflater inflater, <span class="meta">@Nullable</span> ViewGroup container, <span class="meta">@Nullable</span> Bundle savedInstanceState)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">if</span> (mView == <span class="keyword">null</span>) &#123;</span><br><span class="line">            mView = inflater.inflate(R.layout.dialog_confirm_gesture, container, <span class="keyword">false</span>);</span><br><span class="line">        &#125;</span><br><span class="line">        setStyle(STYLE_NORMAL, R.style.ConfirmDialogStyle);</span><br><span class="line">        getDialog().getWindow().setBackgroundDrawable(<span class="keyword">new</span> ColorDrawable(Color.TRANSPARENT));</span><br><span class="line">        <span class="keyword">return</span> mView;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">onViewCreated</span><span class="params">(<span class="meta">@NonNull</span> View view, <span class="meta">@Nullable</span> Bundle savedInstanceState)</span> </span>&#123;</span><br><span class="line">        mImg = mView.findViewById(R.id.img);</span><br><span class="line">        mBtn = mView.findViewById(R.id.btn_submit);</span><br><span class="line">        mInput = mView.findViewById(R.id.input);</span><br><span class="line"></span><br><span class="line">        mBtn.setOnClickListener(<span class="keyword">new</span> View.OnClickListener() &#123;</span><br><span class="line">            <span class="meta">@Override</span></span><br><span class="line">            <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">onClick</span><span class="params">(View view)</span> </span>&#123;</span><br><span class="line">                <span class="keyword">if</span> (mConfirmListener != <span class="keyword">null</span>)&#123;</span><br><span class="line">                    view.setTag( mInput.getText().toString() );</span><br><span class="line">                    mConfirmListener.onClick(view);</span><br><span class="line">                &#125;</span><br><span class="line">                dismiss();</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;);</span><br><span class="line"></span><br><span class="line">        initData();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">initData</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        Bundle bundle = getArguments();</span><br><span class="line">        <span class="keyword">if</span> (bundle != <span class="keyword">null</span>) &#123;</span><br><span class="line">            String name = bundle.getString(KEY_NAME);</span><br><span class="line">            <span class="keyword">if</span> (!TextUtils.isEmpty(name))&#123;</span><br><span class="line">                mInput.setText(name);</span><br><span class="line">            &#125;</span><br><span class="line">            Bitmap bitmap = bundle.getParcelable(KEY_IMG);</span><br><span class="line">            <span class="keyword">if</span> (bitmap != <span class="keyword">null</span>)&#123;</span><br><span class="line">                mImg.setImageBitmap(bitmap);</span><br><span class="line">            &#125;<span class="keyword">else</span> &#123;</span><br><span class="line">                Log.e(<span class="string">&quot;ConfirmDialog&quot;</span>,<span class="string">&quot;bitmap == null&quot;</span>);</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">onStart</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">super</span>.onStart();</span><br><span class="line">        Window window = getDialog().getWindow();</span><br><span class="line">        window.setDimAmount(<span class="number">0.2f</span>);<span class="comment">//设置亮度</span></span><br><span class="line">        window.setGravity(Gravity.CENTER);</span><br><span class="line">        window.setWindowAnimations(R.style.PopupAnimation);</span><br><span class="line">        WindowManager.LayoutParams layoutParams = window.getAttributes();</span><br><span class="line">        layoutParams.width = (<span class="keyword">int</span>) (<span class="number">0.85</span>*deviceWidth(getContext()));</span><br><span class="line">        window.setLayout(layoutParams.width, layoutParams.height);</span><br><span class="line">        window.setBackgroundDrawableResource(android.R.color.transparent);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">int</span> <span class="title">deviceWidth</span><span class="params">(Context context)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> context.getResources().getDisplayMetrics().widthPixels;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">setConfirmListener</span><span class="params">(View.OnClickListener listener)</span></span>&#123;</span><br><span class="line">        mConfirmListener = listener;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre>

<h2 id="4-2-res-layout-dialog-confirm-gesture-xml"><a href="#4-2-res-layout-dialog-confirm-gesture-xml" class="headerlink" title="4.2 res/layout/dialog_confirm_gesture.xml"></a>4.2 res/layout/dialog_confirm_gesture.xml</h2><pre class="highlight"><span class="line"><span class="meta">&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">RelativeLayout</span> <span class="attr">xmlns:android</span>=<span class="string">&quot;http://schemas.android.com/apk/res/android&quot;</span></span></span><br><span class="line"><span class="tag">    <span class="attr">android:layout_width</span>=<span class="string">&quot;match_parent&quot;</span></span></span><br><span class="line"><span class="tag">    <span class="attr">android:layout_height</span>=<span class="string">&quot;wrap_content&quot;</span></span></span><br><span class="line"><span class="tag">    <span class="attr">android:background</span>=<span class="string">&quot;@drawable/shape_white_bg_5_radius&quot;</span></span></span><br><span class="line"><span class="tag">    <span class="attr">android:paddingLeft</span>=<span class="string">&quot;17dp&quot;</span></span></span><br><span class="line"><span class="tag">    <span class="attr">android:paddingRight</span>=<span class="string">&quot;18dp&quot;</span></span></span><br><span class="line"><span class="tag">    <span class="attr">android:paddingBottom</span>=<span class="string">&quot;20dp&quot;</span>&gt;</span></span><br><span class="line">    &lt;ImageView</span><br><span class="line">        android:id=&quot;@+id/img&quot;</span><br><span class="line">        android:layout_width=&quot;100dp&quot;</span><br><span class="line">        android:layout_height=&quot;100dp&quot;</span><br><span class="line">        android:layout_centerHorizontal=&quot;true&quot;</span><br><span class="line">        android:layout_marginTop=&quot;24dp&quot;</span><br><span class="line">        android:src=&quot;@mipmap/ic_launcher&quot; /&gt;</span><br><span class="line">    &lt;EditText</span><br><span class="line">        android:id=&quot;@+id/input&quot;</span><br><span class="line">        android:layout_width=&quot;match_parent&quot;</span><br><span class="line">        android:layout_height=&quot;wrap_content&quot;</span><br><span class="line">        android:layout_below=&quot;@id/img&quot;</span><br><span class="line">        android:layout_marginTop=&quot;8dp&quot;</span><br><span class="line">        android:background=&quot;@drawable/shape_gray_stroke_radius_5&quot;</span><br><span class="line">        android:hint=&quot;输入&quot;</span><br><span class="line">        android:inputType=&quot;text&quot;</span><br><span class="line">        android:minHeight=&quot;45dp&quot;</span><br><span class="line">        android:padding=&quot;8dp&quot;</span><br><span class="line">        android:textColor=&quot;#404040&quot;</span><br><span class="line">        android:textSize=&quot;14sp&quot; /&gt;</span><br><span class="line">    &lt;Button</span><br><span class="line">        android:id=&quot;@+id/btn_submit&quot;</span><br><span class="line">        android:layout_width=&quot;match_parent&quot;</span><br><span class="line">        android:layout_height=&quot;wrap_content&quot;</span><br><span class="line">        android:layout_below=&quot;@id/input&quot;</span><br><span class="line">        android:layout_marginTop=&quot;12dp&quot;</span><br><span class="line">        android:background=&quot;@drawable/shape_blue_radius_5&quot;</span><br><span class="line">        android:text=&quot;添加&quot;</span><br><span class="line">        android:textColor=&quot;#fff&quot;</span><br><span class="line">        android:textSize=&quot;18sp&quot; /&gt;</span><br><span class="line"><span class="tag">&lt;/<span class="name">RelativeLayout</span>&gt;</span></span><br></pre>

<h2 id="4-3-res-values-styles-xml"><a href="#4-3-res-values-styles-xml" class="headerlink" title="4.3 res/values/styles.xml"></a>4.3 res/values/styles.xml</h2><pre class="highlight"><span class="line"><span class="tag">&lt;<span class="name">resources</span>&gt;</span></span><br><span class="line">    <span class="comment">&lt;!-- Base application theme. --&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">style</span> <span class="attr">name</span>=<span class="string">&quot;AppTheme&quot;</span> <span class="attr">parent</span>=<span class="string">&quot;Theme.AppCompat.Light.DarkActionBar&quot;</span>&gt;</span></span><br><span class="line"><span class="xml">        <span class="comment">&lt;!-- Customize your theme here. --&gt;</span></span></span><br><span class="line"><span class="xml">        <span class="tag">&lt;<span class="name">item</span> <span class="attr">name</span>=<span class="string">&quot;colorPrimary&quot;</span>&gt;</span>@color/colorPrimary<span class="tag">&lt;/<span class="name">item</span>&gt;</span></span></span><br><span class="line"><span class="xml">        <span class="tag">&lt;<span class="name">item</span> <span class="attr">name</span>=<span class="string">&quot;colorPrimaryDark&quot;</span>&gt;</span>@color/colorPrimaryDark<span class="tag">&lt;/<span class="name">item</span>&gt;</span></span></span><br><span class="line"><span class="xml">        <span class="tag">&lt;<span class="name">item</span> <span class="attr">name</span>=<span class="string">&quot;colorAccent&quot;</span>&gt;</span>@color/colorAccent<span class="tag">&lt;/<span class="name">item</span>&gt;</span></span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">style</span>&gt;</span></span><br><span class="line"></span><br><span class="line">    </span><br><span class="line">    <span class="tag">&lt;<span class="name">style</span> <span class="attr">name</span>=<span class="string">&quot;ConfirmDialogStyle&quot;</span> <span class="attr">parent</span>=<span class="string">&quot;android:Theme.Holo.Light.Dialog&quot;</span>&gt;</span></span><br><span class="line"><span class="xml">        <span class="tag">&lt;<span class="name">item</span> <span class="attr">name</span>=<span class="string">&quot;android:windowNoTitle&quot;</span>&gt;</span>true<span class="tag">&lt;/<span class="name">item</span>&gt;</span></span></span><br><span class="line"><span class="xml">        <span class="tag">&lt;<span class="name">item</span> <span class="attr">name</span>=<span class="string">&quot;android:windowBackground&quot;</span>&gt;</span>@null<span class="tag">&lt;/<span class="name">item</span>&gt;</span></span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">style</span>&gt;</span></span><br><span class="line">    <span class="comment">&lt;!-- 弹出窗体的动画 从底部弹出 --&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">style</span> <span class="attr">name</span>=<span class="string">&quot;PopupAnimation&quot;</span> <span class="attr">parent</span>=<span class="string">&quot;@android:style/Animation&quot;</span>&gt;</span></span><br><span class="line"><span class="xml">        <span class="comment">&lt;!-- 边框 --&gt;</span></span></span><br><span class="line"><span class="xml">        <span class="tag">&lt;<span class="name">item</span> <span class="attr">name</span>=<span class="string">&quot;android:windowFrame&quot;</span>&gt;</span>@null<span class="tag">&lt;/<span class="name">item</span>&gt;</span></span></span><br><span class="line"><span class="xml">        <span class="comment">&lt;!-- 设置dialog的背景 --&gt;</span></span></span><br><span class="line"><span class="xml">        <span class="tag">&lt;<span class="name">item</span> <span class="attr">name</span>=<span class="string">&quot;android:windowBackground&quot;</span>&gt;</span>@android:color/transparent<span class="tag">&lt;/<span class="name">item</span>&gt;</span></span></span><br><span class="line"><span class="xml">        <span class="comment">&lt;!-- 是否浮现在activity之上 --&gt;</span></span></span><br><span class="line"><span class="xml">        <span class="tag">&lt;<span class="name">item</span> <span class="attr">name</span>=<span class="string">&quot;android:windowIsFloating&quot;</span>&gt;</span>true<span class="tag">&lt;/<span class="name">item</span>&gt;</span></span></span><br><span class="line"><span class="xml">        <span class="comment">&lt;!-- 半透明 --&gt;</span></span></span><br><span class="line"><span class="xml">        <span class="tag">&lt;<span class="name">item</span> <span class="attr">name</span>=<span class="string">&quot;android:windowIsTranslucent&quot;</span>&gt;</span>false<span class="tag">&lt;/<span class="name">item</span>&gt;</span></span></span><br><span class="line"><span class="xml">        <span class="comment">&lt;!-- 无标题 --&gt;</span></span></span><br><span class="line"><span class="xml">        <span class="tag">&lt;<span class="name">item</span> <span class="attr">name</span>=<span class="string">&quot;android:windowNoTitle&quot;</span>&gt;</span>true<span class="tag">&lt;/<span class="name">item</span>&gt;</span></span></span><br><span class="line"><span class="xml">        <span class="comment">&lt;!-- 模糊 --&gt;</span></span></span><br><span class="line"><span class="xml">        <span class="tag">&lt;<span class="name">item</span> <span class="attr">name</span>=<span class="string">&quot;android:backgroundDimEnabled&quot;</span>&gt;</span>true<span class="tag">&lt;/<span class="name">item</span>&gt;</span></span></span><br><span class="line"><span class="xml">        <span class="tag">&lt;<span class="name">item</span> <span class="attr">name</span>=<span class="string">&quot;android:windowEnterAnimation&quot;</span>&gt;</span>@anim/popup_enter<span class="tag">&lt;/<span class="name">item</span>&gt;</span></span></span><br><span class="line"><span class="xml">        <span class="tag">&lt;<span class="name">item</span> <span class="attr">name</span>=<span class="string">&quot;android:windowExitAnimation&quot;</span>&gt;</span>@anim/popup_exit<span class="tag">&lt;/<span class="name">item</span>&gt;</span></span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">style</span>&gt;</span></span><br><span class="line"></span><br><span class="line"><span class="tag">&lt;/<span class="name">resources</span>&gt;</span></span><br></pre>

<h2 id="4-4-res-anim"><a href="#4-4-res-anim" class="headerlink" title="4.4 res/anim"></a>4.4 res/anim</h2><p>popup_enter.xml</p>
<pre class="highlight"><span class="line"><span class="meta">&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">set</span> <span class="attr">xmlns:android</span>=<span class="string">&quot;http://schemas.android.com/apk/res/android&quot;</span> &gt;</span></span><br><span class="line">    &lt;translate</span><br><span class="line">        android:duration=&quot;600&quot;</span><br><span class="line">        android:fromXDelta=&quot;0.0%&quot;</span><br><span class="line">        android:fromYDelta=&quot;100%p&quot;</span><br><span class="line">        android:toXDelta=&quot;0.0%&quot;</span><br><span class="line">        android:toYDelta=&quot;0&quot; /&gt;</span><br><span class="line"><span class="tag">&lt;/<span class="name">set</span>&gt;</span></span><br></pre>

<p>popup_exit.xml</p>
<pre class="highlight"><span class="line"><span class="meta">&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">set</span> <span class="attr">xmlns:android</span>=<span class="string">&quot;http://schemas.android.com/apk/res/android&quot;</span> &gt;</span></span><br><span class="line">    &lt;translate</span><br><span class="line">        android:duration=&quot;600&quot;</span><br><span class="line">        android:fromYDelta=&quot;0&quot;</span><br><span class="line">        android:toYDelta=&quot;100%p&quot; /&gt;</span><br><span class="line"><span class="tag">&lt;/<span class="name">set</span>&gt;</span></span><br></pre>


<h2 id="4-5-res-drawable"><a href="#4-5-res-drawable" class="headerlink" title="4.5 res/drawable"></a>4.5 res/drawable</h2><p>shape_blue_radius_5.xml</p>
<pre class="highlight"><span class="line"><span class="meta">&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">shape</span> <span class="attr">xmlns:android</span>=<span class="string">&quot;http://schemas.android.com/apk/res/android&quot;</span></span></span><br><span class="line"><span class="tag">    <span class="attr">android:shape</span>=<span class="string">&quot;rectangle&quot;</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">corners</span> <span class="attr">android:radius</span>=<span class="string">&quot;5dp&quot;</span>/&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">solid</span> <span class="attr">android:color</span>=<span class="string">&quot;#5577fb&quot;</span>/&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">shape</span>&gt;</span></span><br></pre>

<p>shape_gray_stroke_radius_5.xml</p>
<pre class="highlight"><span class="line"><span class="meta">&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">shape</span> <span class="attr">xmlns:android</span>=<span class="string">&quot;http://schemas.android.com/apk/res/android&quot;</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">corners</span> <span class="attr">android:bottomLeftRadius</span>=<span class="string">&quot;3dp&quot;</span></span></span><br><span class="line"><span class="tag">        <span class="attr">android:bottomRightRadius</span>=<span class="string">&quot;3dp&quot;</span></span></span><br><span class="line"><span class="tag">        <span class="attr">android:topLeftRadius</span>=<span class="string">&quot;3dp&quot;</span></span></span><br><span class="line"><span class="tag">        <span class="attr">android:topRightRadius</span>=<span class="string">&quot;3dp&quot;</span></span></span><br><span class="line"><span class="tag">        /&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">solid</span> <span class="attr">android:color</span>=<span class="string">&quot;#fff&quot;</span>/&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">stroke</span> <span class="attr">android:color</span>=<span class="string">&quot;#bfbfbf&quot;</span> <span class="attr">android:width</span>=<span class="string">&quot;1dp&quot;</span>/&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">shape</span>&gt;</span></span><br></pre>

<p>shape_white_bg_5_radius.xml</p>
<pre class="highlight"><span class="line"><span class="meta">&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">shape</span> <span class="attr">xmlns:android</span>=<span class="string">&quot;http://schemas.android.com/apk/res/android&quot;</span></span></span><br><span class="line"><span class="tag">    <span class="attr">android:shape</span>=<span class="string">&quot;rectangle&quot;</span></span></span><br><span class="line"><span class="tag">    &gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">solid</span> <span class="attr">android:color</span>=<span class="string">&quot;#fff&quot;</span> /&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">corners</span> <span class="attr">android:radius</span>=<span class="string">&quot;5dp&quot;</span>/&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">shape</span>&gt;</span></span><br></pre>

<h2 id="4-6-res-layout-activity-main-xml"><a href="#4-6-res-layout-activity-main-xml" class="headerlink" title="4.6 res/layout/activity_main.xml"></a>4.6 res/layout/activity_main.xml</h2><pre class="highlight"><span class="line"><span class="meta">&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">RelativeLayout</span> <span class="attr">xmlns:android</span>=<span class="string">&quot;http://schemas.android.com/apk/res/android&quot;</span></span></span><br><span class="line"><span class="tag">    <span class="attr">xmlns:app</span>=<span class="string">&quot;http://schemas.android.com/apk/res-auto&quot;</span></span></span><br><span class="line"><span class="tag">    <span class="attr">xmlns:tools</span>=<span class="string">&quot;http://schemas.android.com/tools&quot;</span></span></span><br><span class="line"><span class="tag">    <span class="attr">android:layout_width</span>=<span class="string">&quot;match_parent&quot;</span></span></span><br><span class="line"><span class="tag">    <span class="attr">android:layout_height</span>=<span class="string">&quot;match_parent&quot;</span></span></span><br><span class="line"><span class="tag">    <span class="attr">tools:context</span>=<span class="string">&quot;.MainActivity&quot;</span>&gt;</span></span><br><span class="line">    &lt;LinearLayout</span><br><span class="line">        android:layout_width=&quot;match_parent&quot;</span><br><span class="line">        android:layout_height=&quot;match_parent&quot;</span><br><span class="line">        android:gravity=&quot;center_horizontal&quot;</span><br><span class="line">        android:orientation=&quot;vertical&quot;&gt;</span><br><span class="line">        &lt;Button</span><br><span class="line">            android:id=&quot;@+id/text1&quot;</span><br><span class="line">            android:text=&quot;绘制手势&quot;</span><br><span class="line">            android:textAllCaps=&quot;false&quot;</span><br><span class="line">            android:textSize=&quot;18sp&quot;</span><br><span class="line">            android:background=&quot;@android:color/holo_orange_light&quot;</span><br><span class="line">            android:layout_marginTop=&quot;10dp&quot;</span><br><span class="line">            android:layout_width=&quot;wrap_content&quot;</span><br><span class="line">            android:layout_height=&quot;wrap_content&quot; /&gt;</span><br><span class="line">        &lt;Button</span><br><span class="line">            android:id=&quot;@+id/text2&quot;</span><br><span class="line">            android:text=&quot;识别手势&quot;</span><br><span class="line">            android:textSize=&quot;18sp&quot;</span><br><span class="line">            android:layout_marginTop=&quot;10dp&quot;</span><br><span class="line">            android:background=&quot;@android:color/holo_green_light&quot;</span><br><span class="line">            android:layout_width=&quot;wrap_content&quot;</span><br><span class="line">            android:layout_height=&quot;wrap_content&quot; /&gt;</span><br><span class="line"></span><br><span class="line">    <span class="tag">&lt;/<span class="name">LinearLayout</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">RelativeLayout</span>&gt;</span></span><br></pre>

<h2 id="4-7-MainActivity-java"><a href="#4-7-MainActivity-java" class="headerlink" title="4.7 MainActivity.java"></a>4.7 MainActivity.java</h2><pre class="highlight"><span class="line"><span class="keyword">package</span> com.cupster.android_x_frame;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> android.content.Intent;</span><br><span class="line"><span class="keyword">import</span> android.os.Bundle;</span><br><span class="line"><span class="keyword">import</span> android.view.View;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> androidx.appcompat.app.AppCompatActivity;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">MainActivity</span> <span class="keyword">extends</span> <span class="title">AppCompatActivity</span> </span>&#123;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">protected</span> <span class="keyword">void</span> <span class="title">onCreate</span><span class="params">(Bundle savedInstanceState)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">super</span>.onCreate(savedInstanceState);</span><br><span class="line">        setContentView(R.layout.activity_main);</span><br><span class="line"></span><br><span class="line">        findViewById(R.id.text1).setOnClickListener(<span class="keyword">new</span> View.OnClickListener() &#123;</span><br><span class="line">            <span class="meta">@Override</span></span><br><span class="line">            <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">onClick</span><span class="params">(View view)</span> </span>&#123;</span><br><span class="line">                Intent intent = <span class="keyword">new</span> Intent(MainActivity.<span class="keyword">this</span>, DrawGestureActivity.class );</span><br><span class="line">                MainActivity.<span class="keyword">this</span>.startActivity(intent);</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;);</span><br><span class="line">        findViewById(R.id.text2).setOnClickListener(<span class="keyword">new</span> View.OnClickListener() &#123;</span><br><span class="line">            <span class="meta">@Override</span></span><br><span class="line">            <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">onClick</span><span class="params">(View view)</span> </span>&#123;</span><br><span class="line">                Intent intent = <span class="keyword">new</span> Intent(MainActivity.<span class="keyword">this</span>, DetectionActivity.class );</span><br><span class="line">                MainActivity.<span class="keyword">this</span>.startActivity(intent);</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;);</span><br><span class="line"></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre>
<h2 id="4-8-AndroidManifest-xml"><a href="#4-8-AndroidManifest-xml" class="headerlink" title="4.8 AndroidManifest.xml"></a>4.8 AndroidManifest.xml</h2><pre class="highlight"><span class="line"><span class="meta">&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">manifest</span> <span class="attr">xmlns:android</span>=<span class="string">&quot;http://schemas.android.com/apk/res/android&quot;</span></span></span><br><span class="line"><span class="tag">    <span class="attr">package</span>=<span class="string">&quot;com.cupster.android_x_frame&quot;</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">uses-permission</span> <span class="attr">android:name</span>=<span class="string">&quot;android.permission.WRITE_EXTERNAL_STORAGE&quot;</span>/&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">uses-permission</span> <span class="attr">android:name</span>=<span class="string">&quot;android.permission.READ_EXTERNAL_STORAGE&quot;</span>/&gt;</span></span><br><span class="line">    &lt;application</span><br><span class="line">        android:allowBackup=&quot;true&quot;</span><br><span class="line">        android:icon=&quot;@mipmap/ic_launcher&quot;</span><br><span class="line">        android:label=&quot;@string/app_name&quot;</span><br><span class="line">        android:roundIcon=&quot;@mipmap/ic_launcher_round&quot;</span><br><span class="line">        android:supportsRtl=&quot;true&quot;</span><br><span class="line">        android:theme=&quot;@style/AppTheme&quot;&gt;</span><br><span class="line">        <span class="tag">&lt;<span class="name">activity</span> <span class="attr">android:name</span>=<span class="string">&quot;.MainActivity&quot;</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">intent-filter</span>&gt;</span></span><br><span class="line">                <span class="tag">&lt;<span class="name">action</span> <span class="attr">android:name</span>=<span class="string">&quot;android.intent.action.MAIN&quot;</span> /&gt;</span></span><br><span class="line"></span><br><span class="line">                <span class="tag">&lt;<span class="name">category</span> <span class="attr">android:name</span>=<span class="string">&quot;android.intent.category.LAUNCHER&quot;</span> /&gt;</span></span><br><span class="line">            <span class="tag">&lt;/<span class="name">intent-filter</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="name">activity</span>&gt;</span></span><br><span class="line"></span><br><span class="line">        <span class="tag">&lt;<span class="name">activity</span> <span class="attr">android:name</span>=<span class="string">&quot;.DrawGestureActivity&quot;</span></span></span><br><span class="line"><span class="tag">            <span class="attr">android:screenOrientation</span>=<span class="string">&quot;portrait&quot;</span>/&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">activity</span> <span class="attr">android:name</span>=<span class="string">&quot;.DetectionActivity&quot;</span></span></span><br><span class="line"><span class="tag">            <span class="attr">android:screenOrientation</span>=<span class="string">&quot;portrait&quot;</span>/&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">application</span>&gt;</span></span><br><span class="line"></span><br><span class="line"><span class="tag">&lt;/<span class="name">manifest</span>&gt;</span></span><br></pre>


<h2 id="4-9-PermissionUtil-java"><a href="#4-9-PermissionUtil-java" class="headerlink" title="4.9 PermissionUtil.java"></a>4.9 PermissionUtil.java</h2><pre class="highlight"><span class="line"><span class="keyword">package</span> com.cupster.android_x_frame;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> android.Manifest.permission;</span><br><span class="line"><span class="keyword">import</span> android.app.Activity;</span><br><span class="line"><span class="keyword">import</span> android.content.ComponentName;</span><br><span class="line"><span class="keyword">import</span> android.content.Context;</span><br><span class="line"><span class="keyword">import</span> android.content.Intent;</span><br><span class="line"><span class="keyword">import</span> android.content.pm.PackageManager;</span><br><span class="line"><span class="keyword">import</span> android.net.Uri;</span><br><span class="line"><span class="keyword">import</span> android.os.Build;</span><br><span class="line"><span class="keyword">import</span> android.provider.Settings;</span><br><span class="line"><span class="keyword">import</span> android.text.TextUtils;</span><br><span class="line"><span class="keyword">import</span> android.util.Log;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> androidx.core.app.ActivityCompat;</span><br><span class="line"><span class="keyword">import</span> androidx.core.content.ContextCompat;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> *  Encoding by Cupster on 2019/12/24 16:27.</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * 动态申请权限工具类</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">final</span> <span class="class"><span class="keyword">class</span> <span class="title">PermissionUtil</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">final</span> String[] GROUP_CALENDAR      = &#123;</span><br><span class="line">            permission.READ_CALENDAR, permission.WRITE_CALENDAR</span><br><span class="line">    &#125;;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">final</span> String[] GROUP_CAMERA        = &#123;</span><br><span class="line">            permission.CAMERA</span><br><span class="line">    &#125;;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">final</span> String[] GROUP_CONTACTS      = &#123;</span><br><span class="line">            permission.READ_CONTACTS, permission.WRITE_CONTACTS, permission.GET_ACCOUNTS</span><br><span class="line">    &#125;;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">final</span> String[] GROUP_LOCATION      = &#123;</span><br><span class="line">            permission.ACCESS_FINE_LOCATION, permission.ACCESS_COARSE_LOCATION</span><br><span class="line">    &#125;;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">final</span> String[] GROUP_MICROPHONE    = &#123;</span><br><span class="line">            permission.RECORD_AUDIO</span><br><span class="line">    &#125;;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">final</span> String[] GROUP_PHONE         = &#123;</span><br><span class="line">            permission.READ_PHONE_STATE, permission.READ_PHONE_NUMBERS, permission.CALL_PHONE,</span><br><span class="line">            permission.READ_CALL_LOG, permission.WRITE_CALL_LOG, permission.ADD_VOICEMAIL,</span><br><span class="line">            permission.USE_SIP, permission.PROCESS_OUTGOING_CALLS, permission.ANSWER_PHONE_CALLS</span><br><span class="line">    &#125;;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">final</span> String[] GROUP_PHONE_BELOW_O = &#123;</span><br><span class="line">            permission.READ_PHONE_STATE, permission.READ_PHONE_NUMBERS, permission.CALL_PHONE,</span><br><span class="line">            permission.READ_CALL_LOG, permission.WRITE_CALL_LOG, permission.ADD_VOICEMAIL,</span><br><span class="line">            permission.USE_SIP, permission.PROCESS_OUTGOING_CALLS</span><br><span class="line">    &#125;;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">final</span> String[] GROUP_SENSORS       = &#123;</span><br><span class="line">            permission.BODY_SENSORS</span><br><span class="line">    &#125;;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">final</span> String[] GROUP_SMS           = &#123;</span><br><span class="line">            permission.SEND_SMS, permission.RECEIVE_SMS, permission.READ_SMS,</span><br><span class="line">            permission.RECEIVE_WAP_PUSH, permission.RECEIVE_MMS,</span><br><span class="line">    &#125;;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">final</span> String[] GROUP_STORAGE       = &#123;</span><br><span class="line">            permission.READ_EXTERNAL_STORAGE, permission.WRITE_EXTERNAL_STORAGE,</span><br><span class="line">    &#125;;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 申请所有权限</span></span><br><span class="line"><span class="comment">     * 调用后，activity中复写 onRequestPermissionsResult（）处理申请权限结果</span></span><br><span class="line"><span class="comment">     * PERMISSION_DENIED = -1;</span></span><br><span class="line"><span class="comment">     * PERMISSION_GRANTED = 0;</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> context activity</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> requestCode 请求码</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">applyPermission</span><span class="params">(Activity context ,<span class="keyword">int</span> requestCode ,String pkg)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">if</span> (needApply(context ,pkg)) &#123;</span><br><span class="line">            String[] allpermissions =&#123;&#125;;</span><br><span class="line">            <span class="keyword">try</span> &#123;</span><br><span class="line">                allpermissions = context.getPackageManager().getPackageInfo(pkg, PackageManager.GET_PERMISSIONS)</span><br><span class="line">                        .requestedPermissions;</span><br><span class="line">            &#125; <span class="keyword">catch</span> (PackageManager.NameNotFoundException e) &#123;</span><br><span class="line">                Log.e( <span class="string">&quot;permission&quot;</span>,<span class="string">&quot;app has no request any permission&quot;</span> );</span><br><span class="line">            &#125;</span><br><span class="line">            ActivityCompat.requestPermissions( context, allpermissions, requestCode);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 申请指定权限</span></span><br><span class="line"><span class="comment">     * 调用后，activity中复写 onRequestPermissionsResult（）处理申请权限结果</span></span><br><span class="line"><span class="comment">     * PERMISSION_DENIED = -1;</span></span><br><span class="line"><span class="comment">     * PERMISSION_GRANTED = 0;</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> context activity</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> permissions 指定的权限</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">applySignPermission</span><span class="params">(Activity context,<span class="keyword">int</span> requestCode ,String[] permissions )</span> </span>&#123;</span><br><span class="line">        <span class="keyword">if</span> (!checkPermissions(context ,permissions)) &#123;</span><br><span class="line">            ActivityCompat.requestPermissions( context, permissions, requestCode);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">boolean</span> <span class="title">isGranted</span><span class="params">(<span class="keyword">final</span> String... permissions)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">for</span> (String permission : permissions) &#123;</span><br><span class="line">            <span class="keyword">if</span> (!isGranted(permission)) &#123;</span><br><span class="line">                <span class="keyword">return</span> <span class="keyword">false</span>;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">true</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">boolean</span> <span class="title">isGranted</span><span class="params">(Context context ,<span class="keyword">final</span> String permission)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> Build.VERSION.SDK_INT &lt; Build.VERSION_CODES.M</span><br><span class="line">                || PackageManager.PERMISSION_GRANTED</span><br><span class="line">                == ContextCompat.checkSelfPermission(context.getApplicationContext(), permission);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 判断是否有权限限制</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> context activity</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> pkg 包名</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@return</span> 是否需要申请放行权限</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">boolean</span> <span class="title">needApply</span><span class="params">(Activity context ,String pkg )</span></span>&#123;</span><br><span class="line">        <span class="keyword">boolean</span> needApply = <span class="keyword">false</span>;</span><br><span class="line">        <span class="keyword">if</span> (Build.VERSION.SDK_INT &gt;= Build.VERSION_CODES.M) &#123;</span><br><span class="line">            String[] allPermissions =&#123;&#125;;</span><br><span class="line">            <span class="keyword">try</span> &#123;</span><br><span class="line">                allPermissions = context.getPackageManager().getPackageInfo(pkg, PackageManager.GET_PERMISSIONS)</span><br><span class="line">                        .requestedPermissions;</span><br><span class="line">            &#125; <span class="keyword">catch</span> (PackageManager.NameNotFoundException e) &#123;</span><br><span class="line">                Log.e( <span class="string">&quot;permission&quot;</span>,<span class="string">&quot;app has no request any permission&quot;</span> );</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">for</span> (String permission : allPermissions) &#123;</span><br><span class="line">                <span class="keyword">int</span> checkPermission = ContextCompat.checkSelfPermission(context.getApplicationContext(),</span><br><span class="line">                        permission);</span><br><span class="line">                <span class="keyword">if</span> (checkPermission != PackageManager.PERMISSION_GRANTED) &#123;</span><br><span class="line">                    needApply = <span class="keyword">true</span>;</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> needApply;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 检测权限是否授权</span></span><br><span class="line"><span class="comment">     * Activity.onRequestPermissionsResult（）中回调使用</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> permissions 权限数组</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@return</span> true 有权限   false 被拒绝</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="function"><span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">boolean</span> <span class="title">checkPermissions</span><span class="params">(Context activity ,String[] permissions)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">if</span> (Build.VERSION.SDK_INT &lt; Build.VERSION_CODES.M) &#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="keyword">true</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">for</span> (String permission : permissions) &#123;</span><br><span class="line">            <span class="keyword">if</span> (ActivityCompat.checkSelfPermission(activity, permission) !=</span><br><span class="line">                    PackageManager.PERMISSION_GRANTED) &#123;</span><br><span class="line">                <span class="keyword">return</span> <span class="keyword">false</span>;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">true</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">skipPermissionSetting</span><span class="params">(Context context)</span></span>&#123;</span><br><span class="line"><span class="comment">//        String sdk = android.os.Build.VERSION.SDK; // SDK号</span></span><br><span class="line"><span class="comment">//        String model = android.os.Build.MODEL; // 手机型号</span></span><br><span class="line"><span class="comment">//        String release = android.os.Build.VERSION.RELEASE; // android系统版本号</span></span><br><span class="line">        String brand = Build.BRAND;<span class="comment">//手机厂商</span></span><br><span class="line">        <span class="keyword">if</span> (TextUtils.equals(brand.toLowerCase(), <span class="string">&quot;redmi&quot;</span>) || TextUtils.equals(brand.toLowerCase(), <span class="string">&quot;xiaomi&quot;</span>)) &#123;</span><br><span class="line">            gotoMiuiPermission(context);<span class="comment">//小米</span></span><br><span class="line">        &#125; <span class="keyword">else</span> <span class="keyword">if</span> (TextUtils.equals(brand.toLowerCase(), <span class="string">&quot;meizu&quot;</span>)) &#123;</span><br><span class="line">            gotoMeizuPermission(context);</span><br><span class="line">        &#125; <span class="keyword">else</span> <span class="keyword">if</span> (TextUtils.equals(brand.toLowerCase(), <span class="string">&quot;huawei&quot;</span>) || TextUtils.equals(brand.toLowerCase(), <span class="string">&quot;honor&quot;</span>)) &#123;</span><br><span class="line">            gotoHuaweiPermission(context);</span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">            context.startActivity(getAppDetailSettingIntent(context));</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 跳转到miui的权限管理页面</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="function"><span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">gotoMiuiPermission</span><span class="params">(Context context)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">try</span> &#123; <span class="comment">// MIUI 8</span></span><br><span class="line">            Intent localIntent = <span class="keyword">new</span> Intent(<span class="string">&quot;miui.intent.action.APP_PERM_EDITOR&quot;</span>);</span><br><span class="line">            localIntent.setClassName(<span class="string">&quot;com.miui.securitycenter&quot;</span>, <span class="string">&quot;com.miui.permcenter.permissions.PermissionsEditorActivity&quot;</span>);</span><br><span class="line">            localIntent.putExtra(<span class="string">&quot;extra_pkgname&quot;</span>, context.getPackageName());</span><br><span class="line">            context.startActivity(localIntent);</span><br><span class="line">        &#125; <span class="keyword">catch</span> (Exception e) &#123;</span><br><span class="line">            <span class="keyword">try</span> &#123; <span class="comment">// MIUI 5/6/7</span></span><br><span class="line">                Intent localIntent = <span class="keyword">new</span> Intent(<span class="string">&quot;miui.intent.action.APP_PERM_EDITOR&quot;</span>);</span><br><span class="line">                localIntent.setClassName(<span class="string">&quot;com.miui.securitycenter&quot;</span>, <span class="string">&quot;com.miui.permcenter.permissions.AppPermissionsEditorActivity&quot;</span>);</span><br><span class="line">                localIntent.putExtra(<span class="string">&quot;extra_pkgname&quot;</span>, context.getPackageName());</span><br><span class="line">                context.startActivity(localIntent);</span><br><span class="line">            &#125; <span class="keyword">catch</span> (Exception e1) &#123; <span class="comment">// 否则跳转到应用详情</span></span><br><span class="line">                context.startActivity(getAppDetailSettingIntent(context));</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 跳转到魅族的权限管理系统</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="function"><span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">gotoMeizuPermission</span><span class="params">(Context context)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            Intent intent = <span class="keyword">new</span> Intent(<span class="string">&quot;com.meizu.safe.security.SHOW_APPSEC&quot;</span>);</span><br><span class="line">            intent.addCategory(Intent.CATEGORY_DEFAULT);</span><br><span class="line">            intent.putExtra(<span class="string">&quot;packageName&quot;</span>, context.getPackageName());</span><br><span class="line">            context.startActivity(intent);</span><br><span class="line">        &#125; <span class="keyword">catch</span> (Exception e) &#123;</span><br><span class="line">            e.printStackTrace();</span><br><span class="line">            context.startActivity(getAppDetailSettingIntent(context));</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 华为的权限管理页面</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="function"><span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">gotoHuaweiPermission</span><span class="params">(Context context)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            Intent intent = <span class="keyword">new</span> Intent();</span><br><span class="line">            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);</span><br><span class="line">            ComponentName comp = <span class="keyword">new</span> ComponentName(<span class="string">&quot;com.huawei.systemmanager&quot;</span>, <span class="string">&quot;com.huawei.permissionmanager.ui.MainActivity&quot;</span>);<span class="comment">//华为权限管理</span></span><br><span class="line">            intent.setComponent(comp);</span><br><span class="line">            context.startActivity(intent);</span><br><span class="line">        &#125; <span class="keyword">catch</span> (Exception e) &#123;</span><br><span class="line">            e.printStackTrace();</span><br><span class="line">            context.startActivity(getAppDetailSettingIntent(context));</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 获取应用详情页面intent（如果找不到要跳转的界面，也可以先把用户引导到系统设置页面）</span></span><br><span class="line"><span class="comment">     *</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@return</span> Intent</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="function"><span class="keyword">private</span> <span class="keyword">static</span> Intent <span class="title">getAppDetailSettingIntent</span><span class="params">(Context context)</span> </span>&#123;</span><br><span class="line">        Intent localIntent = <span class="keyword">new</span> Intent();</span><br><span class="line">        localIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);</span><br><span class="line">        <span class="keyword">if</span> (Build.VERSION.SDK_INT &gt;= Build.VERSION_CODES.GINGERBREAD) &#123;</span><br><span class="line">            localIntent.setAction(<span class="string">&quot;android.settings.APPLICATION_DETAILS_SETTINGS&quot;</span>);</span><br><span class="line">            localIntent.setData(Uri.fromParts(<span class="string">&quot;package&quot;</span>,context.getPackageName(), <span class="keyword">null</span>));</span><br><span class="line">        &#125; <span class="keyword">else</span> <span class="keyword">if</span> (Build.VERSION.SDK_INT &lt;= Build.VERSION_CODES.FROYO) &#123;</span><br><span class="line">            localIntent.setAction(Intent.ACTION_VIEW);</span><br><span class="line">            localIntent.setClassName(<span class="string">&quot;com.android.settings&quot;</span>, <span class="string">&quot;com.android.settings.InstalledAppDetails&quot;</span>);</span><br><span class="line">            localIntent.putExtra(<span class="string">&quot;com.android.settings.ApplicationPkgName&quot;</span>,context.getPackageName());</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> localIntent;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * Launch the application&#x27;s details settings.</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">launchAppDetailsSettings</span><span class="params">(Context context ,String pkg)</span> </span>&#123;</span><br><span class="line">        Intent intent = <span class="keyword">new</span> Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);</span><br><span class="line">        intent.setData(Uri.parse(<span class="string">&quot;package:&quot;</span> + pkg));</span><br><span class="line">        <span class="keyword">if</span> (!isIntentAvailable( context ,intent)) <span class="keyword">return</span>;</span><br><span class="line">        context.startActivity(intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK));</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">boolean</span> <span class="title">isIntentAvailable</span><span class="params">(Context context ,<span class="keyword">final</span> Intent intent)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> context.getApplicationContext().getPackageManager()</span><br><span class="line">                .queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY)</span><br><span class="line">                .size() &gt; <span class="number">0</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre>






  </div>
  <div>
  
  <div class="post-note note-warning copyright" style="margin-top: 42px">
    <p><span style="font-weight: bold;">作者：</span><a target="_blank" rel="nofollow noopener noreferrer" href="http://example.com/about">Cupster</a></p>
    <p><span style="font-weight: bold;">文章链接：</span><a target="_blank" rel="nofollow noopener noreferrer" href="http://example.com/2019/08/08/018-Android%E8%87%AA%E5%AE%9A%E4%B9%89View(13)%EF%BC%9A%E8%87%AA%E5%AE%9A%E4%B9%89%E6%89%8B%E5%8A%BF%E5%AD%98%E5%82%A8%E5%8F%8A%E4%BD%BF%E7%94%A8%E8%AF%A6%E8%A7%A3(%E5%9B%BE%E6%96%87)/">http://example.com/2019/08/08/018-Android%E8%87%AA%E5%AE%9A%E4%B9%89View(13)%EF%BC%9A%E8%87%AA%E5%AE%9A%E4%B9%89%E6%89%8B%E5%8A%BF%E5%AD%98%E5%82%A8%E5%8F%8A%E4%BD%BF%E7%94%A8%E8%AF%A6%E8%A7%A3(%E5%9B%BE%E6%96%87)/</a></p>
    <p><span style="font-weight: bold;">版权声明：</span>本博客所有文章除特别声明外，均采用<a target="_blank" rel="noopener" href="https://creativecommons.org/licenses/by-nc-sa/4.0/deed.zh">CC BY-NC-SA 4.0 协议</a>。转载请注明出处！</p>
  </div>
  
  </div>
</article>
<div class="nav">
  
  <div class="nav-item-prev">
    <a href="/2019/08/12/019-Android自定义View(14)：手势处理库android-gesture-detectors详解(图文)/" class="nav-link">
      <i class="iconfont icon-left nav-prev-icon"></i>
      <div>
        <div class="nav-label">上一篇</div>
        
        <div class="nav-title">019-Android自定义View(14)：手势处理库android-gesture-detectors详解(图文) </div>
        
      </div>
    </a>
  </div>
  
  
  <div class="nav-item-next">
    <a href="/2019/08/02/017-Android自定义View(12)：手势绘制及GestureOverlayView事件浅析/" class="nav-link">
      <div>
        <div class="nav-label">下一篇</div>
        
        <div class="nav-title">017-Android自定义View(12)：手势绘制及GestureOverlayView事件浅析 </div>
        
      </div>
      <i class="iconfont icon-right nav-next-icon"></i>
    </a>
  </div>
  
</div>

<div class="card card-content toc-card" id="mobiletoc">
  <div class="toc-header"><i class="iconfont icon-menu" style="padding-right: 2px;"></i>目录</div>
<ol class="toc"><li class="toc-item toc-level-1"><a class="toc-link" href="#1-%E5%9F%BA%E7%A1%80"><span class="toc-text">1.基础</span></a></li><li class="toc-item toc-level-1"><a class="toc-link" href="#2-%E5%AD%98%E5%82%A8%E6%89%8B%E5%8A%BF"><span class="toc-text">2.存储手势</span></a><ol class="toc-child"><li class="toc-item toc-level-2"><a class="toc-link" href="#2-1%E4%BB%A3%E7%A0%81%E5%8F%8A%E6%B3%A8%E9%87%8A"><span class="toc-text">2.1代码及注释</span></a></li></ol></li><li class="toc-item toc-level-1"><a class="toc-link" href="#3-%E8%AF%BB%E5%8F%96-%E4%BD%BF%E7%94%A8%E6%89%8B%E5%8A%BF"><span class="toc-text">3.读取&#x2F;使用手势</span></a></li><li class="toc-item toc-level-1"><a class="toc-link" href="#4-%E9%99%84-%E7%9B%B8%E5%85%B3%E6%AC%A1%E8%A6%81%E4%BB%A3%E7%A0%81"><span class="toc-text">4.附 相关次要代码</span></a><ol class="toc-child"><li class="toc-item toc-level-2"><a class="toc-link" href="#4-1-ConfirmDialog-java"><span class="toc-text">4.1 ConfirmDialog.java</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#4-2-res-layout-dialog-confirm-gesture-xml"><span class="toc-text">4.2 res&#x2F;layout&#x2F;dialog_confirm_gesture.xml</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#4-3-res-values-styles-xml"><span class="toc-text">4.3 res&#x2F;values&#x2F;styles.xml</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#4-4-res-anim"><span class="toc-text">4.4 res&#x2F;anim</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#4-5-res-drawable"><span class="toc-text">4.5 res&#x2F;drawable</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#4-6-res-layout-activity-main-xml"><span class="toc-text">4.6 res&#x2F;layout&#x2F;activity_main.xml</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#4-7-MainActivity-java"><span class="toc-text">4.7 MainActivity.java</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#4-8-AndroidManifest-xml"><span class="toc-text">4.8 AndroidManifest.xml</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#4-9-PermissionUtil-java"><span class="toc-text">4.9 PermissionUtil.java</span></a></li></ol></li></ol>
</div></main>
          <aside class="left-column">
            
            <div class="card card-author">
              
<img src="/img/ic_head.jpg" class="author-img">

<p class="author-name">Cupster</p>
<p class="author-description">深山磨柴斧，一鸣震江湖</p>
<div class="author-message">
  <a class="author-posts-count" href="/archives">
    <span>66</span>
    <span>文章</span>
  </a>
  <a class="author-categories-count" href="/categories">
    <span>5</span>
    <span>分类</span>
  </a>
  <a class="author-tags-count" href="/tags">
    <span>31</span>
    <span>标签</span>
  </a>
</div>

<div class="author-card-society">
  
    <div class="author-card-society-icon">
      <a target="_blank" rel="noopener" href="https://cupster.blog.csdn.net/">
        <i class="iconfont /img/ic_csdn.png society-icon"></i>
      </a>
    </div>
  
</div>

            </div>
            
            <div class="sticky-tablet">
  
  
  <article class="display-when-two-columns spacer">
    <div class="card card-content toc-card">
      <div class="toc-header"><i class="iconfont icon-menu" style="padding-right: 2px;"></i>目录</div>
<ol class="toc"><li class="toc-item toc-level-1"><a class="toc-link" href="#1-%E5%9F%BA%E7%A1%80"><span class="toc-text">1.基础</span></a></li><li class="toc-item toc-level-1"><a class="toc-link" href="#2-%E5%AD%98%E5%82%A8%E6%89%8B%E5%8A%BF"><span class="toc-text">2.存储手势</span></a><ol class="toc-child"><li class="toc-item toc-level-2"><a class="toc-link" href="#2-1%E4%BB%A3%E7%A0%81%E5%8F%8A%E6%B3%A8%E9%87%8A"><span class="toc-text">2.1代码及注释</span></a></li></ol></li><li class="toc-item toc-level-1"><a class="toc-link" href="#3-%E8%AF%BB%E5%8F%96-%E4%BD%BF%E7%94%A8%E6%89%8B%E5%8A%BF"><span class="toc-text">3.读取&#x2F;使用手势</span></a></li><li class="toc-item toc-level-1"><a class="toc-link" href="#4-%E9%99%84-%E7%9B%B8%E5%85%B3%E6%AC%A1%E8%A6%81%E4%BB%A3%E7%A0%81"><span class="toc-text">4.附 相关次要代码</span></a><ol class="toc-child"><li class="toc-item toc-level-2"><a class="toc-link" href="#4-1-ConfirmDialog-java"><span class="toc-text">4.1 ConfirmDialog.java</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#4-2-res-layout-dialog-confirm-gesture-xml"><span class="toc-text">4.2 res&#x2F;layout&#x2F;dialog_confirm_gesture.xml</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#4-3-res-values-styles-xml"><span class="toc-text">4.3 res&#x2F;values&#x2F;styles.xml</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#4-4-res-anim"><span class="toc-text">4.4 res&#x2F;anim</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#4-5-res-drawable"><span class="toc-text">4.5 res&#x2F;drawable</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#4-6-res-layout-activity-main-xml"><span class="toc-text">4.6 res&#x2F;layout&#x2F;activity_main.xml</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#4-7-MainActivity-java"><span class="toc-text">4.7 MainActivity.java</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#4-8-AndroidManifest-xml"><span class="toc-text">4.8 AndroidManifest.xml</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#4-9-PermissionUtil-java"><span class="toc-text">4.9 PermissionUtil.java</span></a></li></ol></li></ol>
    </div>
  </article>
  
  
  <article class="card card-content categories-widget">
    <div class="categories-card">
  <div class="categories-header"><i class="iconfont icon-fenlei" style="padding-right: 2px;"></i>分类</div>
  <div class="categories-list">
    
      <a href="/categories/Android/">
        <div class="categories-list-item">
          Android
          <span class="categories-list-item-badge">38</span>
        </div>
      </a>
    
      <a href="/categories/Linux/">
        <div class="categories-list-item">
          Linux
          <span class="categories-list-item-badge">6</span>
        </div>
      </a>
    
      <a href="/categories/Dev-Base/">
        <div class="categories-list-item">
          Dev-Base
          <span class="categories-list-item-badge">12</span>
        </div>
      </a>
    
      <a href="/categories/Kotlin/">
        <div class="categories-list-item">
          Kotlin
          <span class="categories-list-item-badge">9</span>
        </div>
      </a>
    
      <a href="/categories/自动化脚本/">
        <div class="categories-list-item">
          自动化脚本
          <span class="categories-list-item-badge">1</span>
        </div>
      </a>
    
  </div>
</div>
  </article>
  
  <article class="card card-content tags-widget">
    <div class="tags-card">
  <div class="tags-header"><i class="iconfont icon-biaoqian" style="padding-right: 2px;"></i>热门标签</div>
  <div class="tags-list">
    
    <a href="/tags/Android/" title="Android"><div class="tags-list-item">Android</div></a>
    
    <a href="/tags/Android自定义View/" title="Android自定义View"><div class="tags-list-item">Android自定义View</div></a>
    
    <a href="/tags/MacOS/" title="MacOS"><div class="tags-list-item">MacOS</div></a>
    
    <a href="/tags/Kotlin/" title="Kotlin"><div class="tags-list-item">Kotlin</div></a>
    
    <a href="/tags/Android持久化/" title="Android持久化"><div class="tags-list-item">Android持久化</div></a>
    
    <a href="/tags/CentOS/" title="CentOS"><div class="tags-list-item">CentOS</div></a>
    
    <a href="/tags/Linux/" title="Linux"><div class="tags-list-item">Linux</div></a>
    
    <a href="/tags/Android事件/" title="Android事件"><div class="tags-list-item">Android事件</div></a>
    
    <a href="/tags/Android基础/" title="Android基础"><div class="tags-list-item">Android基础</div></a>
    
    <a href="/tags/Android手势/" title="Android手势"><div class="tags-list-item">Android手势</div></a>
    
    <a href="/tags/Scrcpy/" title="Scrcpy"><div class="tags-list-item">Scrcpy</div></a>
    
    <a href="/tags/Android动画/" title="Android动画"><div class="tags-list-item">Android动画</div></a>
    
    <a href="/tags/Git/" title="Git"><div class="tags-list-item">Git</div></a>
    
    <a href="/tags/Java/" title="Java"><div class="tags-list-item">Java</div></a>
    
    <a href="/tags/Docker/" title="Docker"><div class="tags-list-item">Docker</div></a>
    
    <a href="/tags/Android-Dialog/" title="Android Dialog"><div class="tags-list-item">Android Dialog</div></a>
    
  </div>
</div>
  </article>
  
  
</div>
          </aside>
          <aside class="right-column">
            <div class="sticky-widescreen">
  
  
  <article class="card card-content toc-card">
    <div class="toc-header"><i class="iconfont icon-menu" style="padding-right: 2px;"></i>目录</div>
<ol class="toc"><li class="toc-item toc-level-1"><a class="toc-link" href="#1-%E5%9F%BA%E7%A1%80"><span class="toc-text">1.基础</span></a></li><li class="toc-item toc-level-1"><a class="toc-link" href="#2-%E5%AD%98%E5%82%A8%E6%89%8B%E5%8A%BF"><span class="toc-text">2.存储手势</span></a><ol class="toc-child"><li class="toc-item toc-level-2"><a class="toc-link" href="#2-1%E4%BB%A3%E7%A0%81%E5%8F%8A%E6%B3%A8%E9%87%8A"><span class="toc-text">2.1代码及注释</span></a></li></ol></li><li class="toc-item toc-level-1"><a class="toc-link" href="#3-%E8%AF%BB%E5%8F%96-%E4%BD%BF%E7%94%A8%E6%89%8B%E5%8A%BF"><span class="toc-text">3.读取&#x2F;使用手势</span></a></li><li class="toc-item toc-level-1"><a class="toc-link" href="#4-%E9%99%84-%E7%9B%B8%E5%85%B3%E6%AC%A1%E8%A6%81%E4%BB%A3%E7%A0%81"><span class="toc-text">4.附 相关次要代码</span></a><ol class="toc-child"><li class="toc-item toc-level-2"><a class="toc-link" href="#4-1-ConfirmDialog-java"><span class="toc-text">4.1 ConfirmDialog.java</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#4-2-res-layout-dialog-confirm-gesture-xml"><span class="toc-text">4.2 res&#x2F;layout&#x2F;dialog_confirm_gesture.xml</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#4-3-res-values-styles-xml"><span class="toc-text">4.3 res&#x2F;values&#x2F;styles.xml</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#4-4-res-anim"><span class="toc-text">4.4 res&#x2F;anim</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#4-5-res-drawable"><span class="toc-text">4.5 res&#x2F;drawable</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#4-6-res-layout-activity-main-xml"><span class="toc-text">4.6 res&#x2F;layout&#x2F;activity_main.xml</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#4-7-MainActivity-java"><span class="toc-text">4.7 MainActivity.java</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#4-8-AndroidManifest-xml"><span class="toc-text">4.8 AndroidManifest.xml</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#4-9-PermissionUtil-java"><span class="toc-text">4.9 PermissionUtil.java</span></a></li></ol></li></ol>
  </article>
  
  
  <article class="card card-content">
    <div class="recent-posts-card">
  <div class="recent-posts-header"><i class="iconfont icon-wenzhang_huaban" style="padding-right: 2px;"></i>最近文章</div>
  <div class="recent-posts-list">
    
      <div class="recent-posts-item">
        <div class="recent-posts-item-title">2021-03-02</div>
        <a href="/2021/03/02/Git commit规范/"><div class="recent-posts-item-content">Git commit规范</div></a>
      </div>
    
      <div class="recent-posts-item">
        <div class="recent-posts-item-title">2021-02-16</div>
        <a href="/2021/02/16/AutoJS一文精通AutoJS脚本教程详解/"><div class="recent-posts-item-content">AutoJS一文精通AutoJS脚本教程详解</div></a>
      </div>
    
      <div class="recent-posts-item">
        <div class="recent-posts-item-title">2021-01-21</div>
        <a href="/2021/01/21/架构师进阶：注解Annotation全解/"><div class="recent-posts-item-content">架构师进阶：注解Annotation全解</div></a>
      </div>
    
      <div class="recent-posts-item">
        <div class="recent-posts-item-title">2021-01-06</div>
        <a href="/2021/01/06/ConstraintLayout详解/"><div class="recent-posts-item-content">ConstraintLayout详解</div></a>
      </div>
    
  </div>
</div>
  </article>
  
  
</div>
          </aside>
        </div>
      </div>
    </div>
  </div>
  
  <footer class="footer">
  <div class="footer-container">
    <div>
      <div class="footer-dsc">
        <span>Copyright ©
          
          2020 -
          
          2021
        </span>
        &nbsp;
        <a href="/" class="footer-link">不负明天 </a>
      </div>
    </div>

    
    <div class="footer-dsc">
      
      Powered by
      <a href="https://hexo.io/" class="footer-link" target="_blank" rel="nofollow noopener noreferrer">&nbsp;Hexo </a>
      
      
      <span>&nbsp;|&nbsp;</span>
      
      
      Theme -
      <a href="https://github.com/theme-kaze" class="footer-link" target="_blank"
        rel="nofollow noopener noreferrer">&nbsp;Kaze</a>
      
    </div>
    
    
    
    
      <div class="footer-dsc">
        
        本站总访问量686<span id="busuanzi_value_site_pv"></span>次
        
        
        <span>&nbsp;|&nbsp;</span>
        
        
        本站总访客数219<span id="busuanzi_value_site_uv"></span>次
        
      </div>
      
    
</footer>
  <a role="button" id="scrollbutton" class="basebutton"  aria-label="回到顶部">
  <i class="iconfont icon-arrowleft button-icon"></i>
</a>
<a role="button" id="menubutton" class="basebutton">
  <i class="iconfont icon-menu button-icon"></i>
</a>
<a role="button" id="popbutton" class="basebutton" aria-label="控制中心">
  <i class="iconfont icon-expand button-icon"></i>
</a>
<a role="button" id="darkbutton" class="basebutton darkwidget" aria-label="夜色模式">
  <i class="iconfont icon-weather button-icon"></i>
</a>
<a role="button" id="searchbutton" class="basebutton searchwidget" aria-label="搜索">
  <i class="iconfont icon-search button-icon"></i>
</a>

  
  
  
  <script>
  var addImgLayout = function () {
    var img = document.querySelectorAll('.post-content img');
    var i;
    for (i = 0; i < img.length; i++) {
      var wrapper = document.createElement('a');
      wrapper.setAttribute('href', img[i].getAttribute('data-src'));
      wrapper.setAttribute('aria-label', 'illustration');
      wrapper.style.cssText = 'width: 100%; display: flex; justify-content: center;';
      if (img[i].alt) wrapper.dataset.caption = img[i].alt;
      wrapper.dataset.nolink = true;
      img[i].before(wrapper);
      wrapper.append(img[i]);
      var divWrap = document.createElement('div');
      divWrap.classList.add('gallery');
      wrapper.before(divWrap);
      divWrap.append(wrapper);
    }
    baguetteBox.run('.gallery');
  }
</script>
<script>loadScript("/js/lib/lightbox/baguetteBox.min.js", addImgLayout)</script>
  
  
  
<script src="/js/main.js"></script>

  
  <script>loadScript("/js/lib/busuanzi.min.js")</script>
  
  
  <script>
    var addLazyload = function () {
      var observer = lozad('.lozad', {
        load: function (el) {
          el.srcset = el.getAttribute('data-src');
        },
        loaded: function (el) {
          el.classList.add('loaded');
        }
      });
      observer.observe();
    }
  </script>
  <script>loadScript("/js/lib/lozad.min.js", addLazyload)</script>
  
  
</body>

</html>